// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef WM_GPU_FOREIGN_WINDOW_TEXTURE_FACTORY_H_
#define WM_GPU_FOREIGN_WINDOW_TEXTURE_FACTORY_H_

#include <deque>

#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "content/browser/renderer_host/image_transport_factory.h"
#include "ui/compositor/compositor.h"
#include "ui/gfx/native_widget_types.h"

namespace cc {
class ContextProvider;
}

namespace content {
class GpuChannelHostFactory;
}

namespace wm {

// This class provides a way to get notified when textures get lost.
class ForeignWindowTextureFactoryObserver {
 public:
  virtual ~ForeignWindowTextureFactoryObserver() {}

  // Notifies that the textures generated by ForeignWindowTextureFactory were
  // lost.
  virtual void OnLostResources() = 0;
};

// This class provides the interface for notifying the texture implementation
// that contents has changed.
class ForeignWindowTexture : public ui::Texture,
                             public ForeignWindowTextureFactoryObserver {
 public:
  // Overridden from ui::Texture:
  virtual unsigned int PrepareTexture() OVERRIDE;
  virtual WebKit::WebGraphicsContext3D* HostContext3D() OVERRIDE;

  // ForeignWindowTextureFactoryObserver overrides:
  virtual void OnLostResources() OVERRIDE;

  // Indicate that foreign window contents have changed.
  void OnContentsChanged();

  // Add callback that will run when PrepareTexture() is called.
  void AddOnPrepareTextureCallback(const base::Closure& callback);

 protected:
  virtual ~ForeignWindowTexture();

 private:
  friend class ForeignWindowTextureFactory;

  ForeignWindowTexture(content::GpuChannelHostFactory* factory,
                       cc::ContextProvider* context_provider,
                       bool flipped,
                       const gfx::Size& size,
                       float device_scale_factor,
                       int32 image_id);

  void RunOnPrepareTextureCallbacks();

  content::GpuChannelHostFactory* factory_;
  scoped_refptr<cc::ContextProvider> context_provider_;
  int32 image_id_;
  unsigned texture_id_;
  bool contents_changed_;
  std::deque<base::Closure> on_prepare_texture_callbacks_;
};

// This class provides the interface for creating textures bound to foreign
// windows. The factory is a process-wide singleton.
class ForeignWindowTextureFactory
    : public content::ImageTransportFactoryObserver {
 public:
  typedef base::Callback<void(scoped_refptr<ForeignWindowTexture>)>
      CreateTextureCallback;

  // Initialize the global texture factory.
  static void Initialize();

  // Terminates the global texture factory.
  static void Terminate();

  // Gets the factory instance.
  static ForeignWindowTextureFactory* GetInstance();

  // ImageTransportFactoryObserver overrides:
  virtual void OnLostResources() OVERRIDE;

  // Create a texture from a foreign window handle.
  void CreateTextureForForeignWindow(
      gfx::PluginWindowHandle window_handle,
      bool flipped,
      float device_scale_factor,
      const CreateTextureCallback& callback);

  void AddObserver(ForeignWindowTextureFactoryObserver* observer);
  void RemoveObserver(ForeignWindowTextureFactoryObserver* observer);

 private:
  explicit ForeignWindowTextureFactory(
      content::GpuChannelHostFactory* factory);
  virtual ~ForeignWindowTextureFactory();

  int GenerateImageID();

  void OnImageCreated(const CreateTextureCallback& callback,
                      scoped_refptr<cc::ContextProvider> context_provider,
                      bool flipped,
                      float device_scale_factor,
                      int32 image_id,
                      const gfx::Size size);

  static ForeignWindowTextureFactory* instance_;

  content::GpuChannelHostFactory* factory_;

  ObserverList<ForeignWindowTextureFactoryObserver> observer_list_;

  DISALLOW_COPY_AND_ASSIGN(ForeignWindowTextureFactory);
};

}  // namespace wm

#endif  // WM_GPU_FOREIGN_WINDOW_TEXTURE_FACTORY_H_
